'use strict'
//  一、函数 基本上所有的高级语言都支持函数，JavaScript也不例外。JavaScript的函数不但是“头等公民”，而且可以像变量一样使用，具有非常强大的抽象能力。

/* 
语法：

function abs(x) {
    if (x >= 0) {
        return x;
    } else {
        return -x;
    }
}


请注意，函数体内部的语句在执行时，一旦执行到return时，函数就执行完毕，并将结果返回
如果没有return语句，函数执行完毕后也会返回结果，只是结果为undefined。
JavaScript的函数也是一个对象，上述定义的abs()函数实际上是一个函数对象，而函数名abs可以视为指向该函数的变量

第二种语法：

var abs = function (x) {
    if (x >= 0) {
        return x;
    } else {
        return -x;
    }
};

在这种方式下，function (x) { ... }是一个匿名函数，它没有函数名。但是，这个匿名函数赋值给了变量abs，所以，通过变量abs就可以调用该函数

*/

// 二、函数的调用

/* 
正常情况的调用：

abs(10); // 返回10
abs(-9); // 返回9



JavaScript允许传入任意个参数而不影响调用，因此传入的参数比定义的参数多也没有问题，虽然函数内部并不需要这些参数
abs(10, 'blablabla'); // 返回10
abs(-9, 'haha', 'hehe', null); // 返回9


传入的参数比定义的少也没有问题：

abs(); // 返回NaN


这里abs(x)函数的参数x将收到undefined，计算结果为NaN。

要避免收到undefined，可以对参数进行检查：

function abs(x) {
    if (typeof x !== 'number') {
        throw 'Not a number';
    }
    if (x >= 0) {
        return x;
    } else {
        return -x;
    }
}

*/

/*
arguments
JavaScript还有一个免费赠送的关键字arguments，它只在函数内部起作用，并且永远指向当前函数的调用者传入的所有参数。arguments类似Array但它不是一个Array

function foo(x) {
    console.log('x = ' + x); // 10
    for (var i=0; i<arguments.length; i++) {
        console.log('arg ' + i + ' = ' + arguments[i]); // 10, 20, 30
    }
}

foo(10, 20, 30);


arguments最常用于判断传入参数的个数


*/

function abc(){
    var result=0;
    for(let i=0;i<arguments.length;i++){
        result+=arguments[i];
    }
    return result;
}

console.log(abc(1,3,5,7,9));

/*
rest参数
由于JavaScript函数允许接收任意个参数，于是我们就不得不用arguments来获取所有参数：

function foo(a, b) {
    var i, rest = [];
    if (arguments.length > 2) {
        for (i = 2; i<arguments.length; i++) {
            rest.push(arguments[i]);
        }
    }
    console.log('a = ' + a);
    console.log('b = ' + b);
    console.log(rest);
}

为了获取除了已定义参数a、b之外的参数，我们不得不用arguments，并且循环要从索引2开始以便排除前两个参数，这种写法很别扭，只是为了获得额外的rest参数，有没有更好的方法？

ES6标准引入了rest参数，上面的函数可以改写为：

function foo(a, b, ...rest) {
    console.log('a = ' + a);
    console.log('b = ' + b);
    console.log(rest);
}

foo(1, 2, 3, 4, 5);
// 结果:
// a = 1
// b = 2
// Array [ 3, 4, 5 ]

foo(1);
// 结果:
// a = 1
// b = undefined
// Array []


rest参数只能写在最后，前面用...标识，从运行结果可知，传入的参数先绑定a、b，多余的参数以数组形式交给变量rest，所以，不再需要arguments我们就获取了全部参数。

如果传入的参数连正常定义的参数都没填满，也不要紧，rest参数会接收一个空数组（注意不是undefined）。

*/


/*
请用rest参数编写一个sum()函数，接收任意个参数并返回它们的和


*/

function sum(...rest){
    var result=0;
    for(var i=0;i<rest.length;i++){
        result+=rest[i];
    }
    return result;
}


console.log(sum(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17));

/*
练习
定义一个计算圆面积的函数area_of_circle()，它有两个参数：

r: 表示圆的半径；
pi: 表示π的值，如果不传，则默认3.14


*/

function area_of_circle(r,pi){
    if( pi===undefined){
        pi=3.14;
    }
    return r*r*pi;
}

console.log( area_of_circle(2));
console.log( area_of_circle(2,3.1416));